package com.mall.order.services;

import com.mall.commons.tool.exception.ProcessException;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mall.order.OrderCoreService;
import com.mall.order.biz.TransOutboundInvoker;
import com.mall.order.biz.context.AbsTransHandlerContext;
import com.mall.order.biz.factory.OrderProcessPipelineFactory;
import com.mall.order.constant.OrderRetCode;
import com.mall.order.constants.OrderConstants;
import com.mall.order.dal.entitys.Order;
import com.mall.order.dal.entitys.OrderItem;
import com.mall.order.dal.entitys.OrderShipping;
import com.mall.order.dal.entitys.Stock;
import com.mall.order.dal.persistence.OrderItemMapper;
import com.mall.order.dal.persistence.OrderMapper;
import com.mall.order.dal.persistence.OrderShippingMapper;
import com.mall.order.dal.persistence.StockMapper;
import com.mall.order.dto.*;
import com.mall.order.mq.Producer;
import com.mall.order.utils.ExceptionProcessorUtils;
import com.mall.user.constants.SysRetCodeConstants;
import com.mall.order.vo.OrderDetailVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.weekend.Weekend;

import java.math.BigDecimal;

/**
 * ciggar
 * create-date: 2019/7/30-上午10:05
 */
@Slf4j
@Component
@Service
public class OrderCoreServiceImpl implements OrderCoreService {

    @Autowired
    OrderMapper orderMapper;

    @Autowired
    OrderItemMapper orderItemMapper;

    @Autowired
    OrderShippingMapper orderShippingMapper;

    @Autowired
    OrderProcessPipelineFactory orderProcessPipelineFactory;

    @Autowired
    StockMapper stockMapper;

    @Autowired
    Producer producer;


    /**
     * 创建订单的处理流程
     *
     * @param request
     * @return
     */
    @Override
    public CreateOrderResponse createOrder(CreateOrderRequest request) {
        CreateOrderResponse response = new CreateOrderResponse();
        try {
            request.requestCheck();
            //创建pipeline对象(通过orderProcessPipelineFactory创建，)
            TransOutboundInvoker invoker = orderProcessPipelineFactory.build(request);

            //启动pipeline
            invoker.start(); //启动流程（pipeline来处理）

            //获取处理结果
            AbsTransHandlerContext context = invoker.getContext();

            //把处理结果转换为response
            response = (CreateOrderResponse) context.getConvert().convertCtx2Respond(context);

        } catch (Exception e) {
            log.error("OrderCoreServiceImpl.createOrder Occur Exception :" + e);
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
            response.setCode("500");
        }

        return response;
    }


    /**
     * 首先要判断是的是订单状态
     * 取消状态和成功支付状态等不需要恢复库存;
     * 如果是初始化状态为0的需要回退库存(改变锁定状态，反正是物理删除，可以不要改变)
     * 删除订单流程：需要删除订单表 订单关联表  地址信息表
     * 以及将商品锁定的数量还原
     *
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public DeleteOrderResponse deleteOrder(DeleteOrderRequest deleteOrderRequest) {
        String orderId = deleteOrderRequest.getOrderId();
        DeleteOrderResponse response = new DeleteOrderResponse();
        Integer status = -1;
        try {
            deleteOrderRequest.requestCheck();
            // 查询状态码
            OrderDetailVO orderDetail = orderMapper.getOrderDetailByOrderId(Long.parseLong(orderId));
            status = orderDetail.getOrderStatus();

            // 状态码为0 表示是未付款的订单 删除时需要归还库存
            // 处理tb_stock表，将锁定的商品还原，通过订单id在order_item表查出商品id和num 然后遍历锁定还原
            if (status == 0) {
                Example example3 = new Example(OrderItem.class);
                Example.Criteria criteria3 = example3.createCriteria();
                criteria3.andEqualTo(orderId);
                List<OrderItem> orderItems = orderItemMapper.selectByExample(example3);

                for (OrderItem item : orderItems) {
                    Long itemId = item.getItemId();
                    Integer num = item.getNum();

                    Stock stock = new Stock();
                    stock.setItemId(itemId);
                    stock.setLockCount(-num);
                    stock.setStockCount(num.longValue());
                    stockMapper.updateStock(stock);
                    log.info("商品的id：{},已经释放库存量：{}", itemId,stock.getStockCount());
                }
            }

            int order = orderMapper.deleteByPrimaryKey(orderId);

            OrderItem orderItem1 = new OrderItem();
            orderItem1.setOrderId(orderId);
            int orderItem = orderItemMapper.delete(orderItem1);

            OrderShipping orderShipping1 = new OrderShipping();
            orderShipping1.setOrderId(orderId);
            int orderShipping = orderShippingMapper.delete(orderShipping1);

            if (order < 1 || orderItem < 1 || orderShipping < 1) {
                log.info("删除订单表的结果为：{}，删除订单关联表的结果为：{}，删除地址表的结果为：{}", order, orderItem, orderShipping);
                throw new ProcessException(OrderRetCode.SYSTEM_ERROR.getCode(),
                        OrderRetCode.SYSTEM_ERROR.getMessage());
            }
            log.info("表已全部删除");
        } catch (Exception e) {
            log.error(OrderRetCode.SYSTEM_ERROR.getMessage());
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }

        response.setCode(SysRetCodeConstants.SUCCESS.getCode());
        response.setMsg(SysRetCodeConstants.SUCCESS.getMessage());
        return response;
    }


    /**
     * 取消订单
     * 第一：order表改变status为7 取消状态
     * 第二：将stock表的锁定数量加回到库存总量上
     * 第三：orderitem表改变status为2 库存已释放
     *
     * @param cancelOrderRequest
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public CancelOrderResponse cancelOrder(CancelOrderRequest cancelOrderRequest) {
        // 将状态码改为7 已经退款，以及将锁定库存归还。
        CancelOrderResponse response = new CancelOrderResponse();
        String orderId = cancelOrderRequest.getOrderId();
        try {
            cancelOrderRequest.requestCheck();
            Order order = new Order();
            // 第一步：设置取消订单状态码
            order.setStatus(OrderConstants.ORDER_STATUS_TRANSACTION_CANCEL);
            Example example = new Example(Order.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo(orderId);
            int update = orderMapper.updateByExampleSelective(order, example);

            if (update < 1) {
                throw new ProcessException(OrderRetCode.SYSTEM_ERROR.getCode(),
                        OrderRetCode.SYSTEM_ERROR.getMessage());
            }

            log.info("状态码已改变为取消状态");

            // 第二步：处理tb_stock表，将锁定的商品还原，通过订单id在order_item表查出商品id和num 然后遍历锁定还原
            Example example2 = new Example(OrderItem.class);
            Example.Criteria criteria2 = example2.createCriteria();
            criteria2.andEqualTo(orderId);
            List<OrderItem> orderItems = orderItemMapper.selectByExample(example2);

            for (OrderItem item : orderItems) {
                Long itemId = item.getItemId();
                Integer num = item.getNum();

                Stock stock = new Stock();
                stock.setItemId(itemId);
                stock.setLockCount(-num);
                stock.setStockCount(num.longValue());
                stockMapper.updateStock(stock);
            }
            log.info("库存已释放");

            // 第三步：orderitem表改变status
            OrderItem orderItem = new OrderItem();
            // 库存已释放状态码
            orderItem.setStatus(OrderConstants.INVENTORY_RELEASE);
            Example example1 = new Example(OrderItem.class);
            Example.Criteria criteria1 = example1.createCriteria();
            criteria1.andEqualTo(orderId);
            int update2 = orderItemMapper.updateByExampleSelective(orderItem, example1);
            if (update2 < 1) {
                throw new ProcessException(OrderRetCode.SYSTEM_ERROR.getCode(),
                        OrderRetCode.SYSTEM_ERROR.getMessage());
            }
            log.info("已修改库存释放状态码");

        } catch (Exception e) {
            log.error(OrderRetCode.SYSTEM_ERROR.getMessage());
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }
        response.setCode(SysRetCodeConstants.SUCCESS.getCode());
        response.setMsg(SysRetCodeConstants.SUCCESS.getMessage());
        return response;
    }


    //获取用户的所有订单
    @Override
    public OrderListResponse getOrders(OrderListRequest orderListRequest) {
        orderListRequest.requestCheck();
        OrderListResponse response = new OrderListResponse();
        try {
            //分页
            PageHelper.startPage(orderListRequest.getPage(), orderListRequest.getSize());

            List<OrderDetailInfo> detailInfoList = orderMapper.selectOrdersByUserId(orderListRequest.getUserId());

            //分页前的原数据量
            PageInfo<OrderDetailInfo> pageInfo = new PageInfo<>(detailInfoList);
            long total = pageInfo.getTotal();

            response.setDetailInfoList(detailInfoList);
            response.setTotal(total);
            response.setCode("000000");
            response.setMsg("成功");
        } catch (Exception e) {
            log.error("查询用户的所有订单时出现了错误" + e);
            ExceptionProcessorUtils.wrapperHandlerException(response, e);
        }

        return response;
    }

    //获取某个订单的详细数据
    @Override
    public OrderDetailVO getOrderDetail(Long orderId, Long uid) {
        if (orderId == null){
            return null;
        }
        OrderDetailVO orderDetailVO = orderMapper.getOrderDetailByOrderId(orderId);
        if (orderDetailVO == null){
            return null;
        }
        if (!uid.equals(orderDetailVO.getUserId())) {
            //说明查询到的订单不是这个用户的,所以对数据进行一些处理,让controller层可以识别
            orderDetailVO.setUserId(null);
            orderDetailVO.setUserName(null);
            return orderDetailVO;
        }

        BigDecimal orderTotal = new BigDecimal("0.0");
        for (OrderItemDto item : orderDetailVO.getGoodsList()) {
            orderTotal = orderTotal.add(item.getTotalFee());
        }
        orderDetailVO.setOrderTotal(orderTotal);

        System.out.println(orderDetailVO);
        return orderDetailVO;
    }

}
